"""
装饰器：
    1、函数作为参数传入另一个函数中
    2、函数名称可以作为返回值return
    3、函数可以当成变量进行赋值
"""

# 1、函数传递回顾
# def func():
#     print("这是func函数！")
#
# def func1(fn):
#     fn()


# 2、函数可以作为返回值返回
# def func():
#     a = 10
#     def inner():
#         nonlocal a
#         a = a + 1
#         print(a)
#         return a
#     return inner
#
#
#
#
# ret= func()
# ret()

# 3、函数名称可以当成变量进行赋值操作
# def func1():
#     a = 10
#     print("func1返回值：",a)
#
# def func2():
#     b = 20
#     print("func2返回值：", b)
#
#
# func1= func2
# print(func1())
# print(func2())

# def guanjia(game):
#
#     def inner():
#         print("游戏加载外挂！")
#         game()
#         print("游戏卸载外挂！\n")
#     return inner
#
# @guanjia
# def play_dnf():
#     print("玩dnf！")
#
# @guanjia #相当于playerWow = guanjia(play_wow) 把play_wow传入到guanjia中
# def play_wow():
#     print("玩魔兽世界！")

# playDnf = guanjia(play_dnf)
# playerWow = guanjia(play_wow)  # guanjia函数将传入的play_wow函数重新封装了一遍后返回
# play_dnf()  #玩家可以调用加了外挂的inner函数
# play_wow()
# play_dnf()  #玩家可以调用加了外挂的inner函数
# play_wow()
# play_dnf()  #玩家可以调用加了外挂的inner函数
# play_wow()  #玩家可以调用加了外挂的inner函数



# 装饰器参数问题
def guanjia(game):
    # * **  标识接收所有参数打包成元组和字典
    def inner(*args, **kwargs):  # args：接收位置参数，一定是元组，kwargs：接收关键字参数，一定是字典key=value
        # 位置参数是定义函数时参数的位置，(parame1,parame2)，调用时也得按这个顺序写入参数
        # 关键字参数是key=value ，跟位置参数类似，只不过加了 哪个参数=值
        print("游戏加载外挂！")
        #
        wow = game(*args, **kwargs)  # 执行了play_wow返回的 勇者未来
        print("inner打印的参数", args, kwargs)
        print("游戏卸载外挂！\n")
        return wow
    return inner

@guanjia
def play_dnf(username, password, hero):
    print("我要开始玩游戏了dnf了，", username, password, hero)
    print("玩dnf！")

@guanjia #相当于playerWow = guanjia(play_wow) 把play_wow传入到guanjia中
def play_wow(a, b):
    print("我要开始玩游戏了wow了，", a, b)
    print("玩魔兽世界！")
    return "勇者未来"


"""
1、调用play_wow()函数，传入两个参数
2、play_wow（）函数有装饰器需要将自己传入到guanjia（game）这个函数中
3、guanjia（game）函数内的inner（）函数开始打印第一个print
4、guanjia（game）函数内调用传入进来的play_wow（）(实际就是game)这个函数，包括入参
5、接着打印两个print（）
6、返回inner并赋值给play_wow
7、其实下边的调用是已经调用完管家函数并且运行完函数体最后赋值给play_wow的结果
8、执行目标函数的时候要有return
"""
print(play_wow(a="zkk", b="123456"))  # 关键字参数
play_dnf("xueyunfei", "789012", "Lzkk")  # 位置参数


"""
装饰器通用写法：
def wrapper(fn):    wrapper:装饰器    fn：目标函数
    def inner(*args, **kwargs)
        # 目前函数前执行
        ret = fn(*args, **kwargs)  # 接收执行了函数的结果
        # 目前函数前执行
        return ret
    return inner
    
@wrapper
def target():
    pass 
### 核心的就是 装饰器的内部函数执行传进来的目标函数
"""

# 一个函数被引用多个装饰器
"""
@1
@2
def target()
@2
@1

"""